package builderaction

import (
	"errors"
	"fmt"
	"reflect"
	"slices"
	"strings"
	"yunj/pkg/yunj/app/service/admin/adminservice"
	"yunj/pkg/yunj/core/builder/builderconsts"
	"yunj/pkg/yunj/core/builder/form"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
)

type ActionInterface interface {
	GetActionCode() (code any, err error)
	SetActionCode(code any) error
	GetActionTitle() (title string, err error)                                 // 获取标题
	SetActionTitle(title string) error                                         // 设置标题
	GetActionType() (typ string, err error)                                    // 获取类型
	SetActionType(typ string) error                                            // 设置类型
	GetActionClass() (class string, err error)                                 // 获取额外的class或图标类名
	SetActionClass(class string) error                                         // 设置额外的class或图标类名
	GetActionUrl() (url string, err error)                                     // 获取触发事件执行的url
	SetActionUrl(url string) error                                             // 设置触发事件执行的url
	GetConfirmFormFields() (res []form.FieldInterface, err error)              // 获取确认表单字段
	GetActionAuth() (auth string, err error)                                   // 获取权限
	SetActionAuth(auth string) error                                           // 设置权限
	GetError() error                                                           // 获取错误
	GetBuilderId() (res string, err error)                                     // 获取构建器ID
	HandleAttr() error                                                         // 处理属性
	RenderHandle(ctx *gin.Context, builderId string) (hasAuth bool, err error) // 渲染处理，返回是否有权限和是否有错误
}

type Action struct {
	Code                   any                                     `json:"code"`
	Title                  string                                  `json:"title"`
	Type                   string                                  `json:"type"`                // 触发事件类型（openTab 打开子页面、openPopup 打开弹出层页面、asyncEvent 异步事件）
	Class                  string                                  `json:"class"`               // 额外的class或图标类名
	Url                    string                                  `json:"url"`                 // 触发事件执行的url
	ConfirmFormFields      []form.FieldInterface                   `json:"confirm_form_fields"` // 确认弹窗表单字段
	ConfirmFormFieldsFuncs []func() ([]form.FieldInterface, error) `json:"-"`                   // 确认弹窗表单字段获取闭包函数
	Auth                   string                                  `json:"auth"`                // 权限key
	BuilderId              string                                  `json:"-"`                   // 构建器id
	GinContext             *gin.Context                            `json:"-"`                   // gin上下文
	ErrPrefix              string                                  `json:"-"`                   // 错误前缀
	Err                    error                                   `json:"-"`                   // 错误

	// 父结构体属性
	actionInstance ActionInterface // 操作实例
}

// 设置操作实例
func SetActionInstance(a *Action, actionInstance ActionInterface) {
	a.actionInstance = actionInstance

	// 获取指针的反射值
	actionInstanceValue := reflect.ValueOf(a.actionInstance)
	// 检查传入的是否为指针
	if actionInstanceValue.Kind() != reflect.Ptr || actionInstanceValue.IsNil() {
		a.SetError("请传入操作实例指针值！")
	}
}

// 获取操作code
func (a *Action) GetActionCode() (res any, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	res = a.Code
	return
}

// 设置操作code
func (a *Action) SetActionCode(code any) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Code = code
	return
}

// 获取标题
func (a *Action) GetActionTitle() (title string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	title = a.Title
	return
}

// 设置标题
func (a *Action) SetActionTitle(title string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Title = title
	return
}

// 获取类型
func (a *Action) GetActionType() (typ string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	typ = a.Type
	return
}

// 设置类型
func (a *Action) SetActionType(typ string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Type = typ
	return
}

// 获取额外的class或图标类名
func (a *Action) GetActionClass() (class string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	class = a.Class 
	return
}

// 设置额外的class或图标类名
func (a *Action) SetActionClass(class string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Class = class
	return
}

// 获取触发事件执行的url
func (a *Action) GetActionUrl() (url string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	url = a.Url
	return
}

// 设置触发事件执行的url
func (a *Action) SetActionUrl(url string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Url = url
	return
}

// 获取确认表单字段
func (a *Action) GetConfirmFormFields() (res []form.FieldInterface, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	res = a.ConfirmFormFields
	return
}

// 设置确认弹窗表单字段
func (a *Action) setConfirmFormFields(fields []form.FieldInterface) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.ConfirmFormFields = fields
	return
}

// 获取确认弹窗表单字段获取闭包函数
func (a *Action) getConfirmFormFieldsFuncs() (res []func() ([]form.FieldInterface, error), err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	res = a.ConfirmFormFieldsFuncs
	return
}

// 设置确认弹窗表单字段获取闭包函数
func (a *Action) setConfirmFormFieldsFuncs(funs []func() ([]form.FieldInterface, error)) (err error) {
	funcs, err := a.getConfirmFormFieldsFuncs()
	if err != nil {
		return
	}
	if funcs == nil {
		funcs = []func() ([]form.FieldInterface, error){}
	}
	funcs = append(funcs, funs...)
	a.ConfirmFormFieldsFuncs = funcs
	return
}

// 获取权限
func (a *Action) GetActionAuth() (auth string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	auth = a.Auth
	return
}

// 设置权限
func (a *Action) SetActionAuth(auth string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.Auth = auth
	return
}

// 获取构建器ID
func (a *Action) GetBuilderId() (res string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	res = a.BuilderId
	return
}

// 设置构建器ID
func (a *Action) setBuilderId(builderId string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.BuilderId = builderId
	return
}

// 设置操作实例的gin上下文
func (a *Action) setGinContext(ctx *gin.Context) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.GinContext = ctx
	return
}

// 获取操作实例的错误前缀
func (a *Action) getErrPrefix() (prefix string, err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	prefix = a.ErrPrefix
	return
}

// 设置操作实例的错误前缀
func (a *Action) setErrPrefix(prefix string) (err error) {
	err = a.GetError()
	if err != nil {
		return
	}
	a.ErrPrefix = prefix
	return
}

// 获取操作错误
func (a *Action) GetError() error {
	return a.Err
}

// 设置操作错误
func (a *Action) SetError(err any) error {
	if _err := a.GetError(); _err != nil {
		return _err
	}
	var resErrMsg string
	if _errMsg, ok := err.(string); ok {
		resErrMsg = _errMsg
	} else if _err, ok := err.(error); ok {
		resErrMsg = _err.Error()
	} else {
		resErrMsg = "未知错误！"
	}

	// 错误前缀
	errPrefix, _ := a.getErrPrefix()
	if errPrefix == "" {
		errPrefix = fmt.Sprintf("操作[%s]", a.Code)
		a.setErrPrefix(errPrefix)
	}

	if !strings.HasPrefix(resErrMsg, errPrefix) {
		resErrMsg = errPrefix + resErrMsg
	}
	newErr := errors.New(resErrMsg)
	a.Err = newErr
	return newErr
}

// 处理属性
func (a *Action) HandleAttr() error {
	return nil
}

// 渲染处理
// @param builderId: 构建器id
// @return hasAuth: 是否有权限
// @return err: 错误消息
func (a *Action) RenderHandle(ctx *gin.Context, builderId string) (hasAuth bool, err error) {
	err = a.setBuilderId(builderId)
	if err != nil {
		return
	}
	// 设置gin上下文
	a.setGinContext(ctx)
	if err = a.GetError(); err != nil {
		return
	}
	// 判断权限
	auth, _ := a.GetActionAuth()
	hasAuth = adminservice.CheckAuth(ctx, auth)
	if !hasAuth {
		return
	}
	// 处理属性
	err = a.actionInstance.HandleAttr()
	if err != nil {
		err = a.SetError(err)
		return
	}
	// 判断url
	typ, _ := a.GetActionType()
	url, _ := a.GetActionUrl()
	if slices.Contains([]string{builderconsts.EVENT_OPEN_POPUP, builderconsts.EVENT_OPEN_TAB}, typ) && url == "" {
		err = errors.New("Action 配置 type=openTab或openPopup时 url 不能为空")
		return
	}
	// 处理class
	class, _ := a.GetActionClass()
	a.SetActionClass(util.IconClass(class))
	// 处理confirm_form_fields
	if err = a.handleRenderConfirmFormFields(); err != nil {
		return
	}
	err = a.GetError()
	return
}

// 处理要渲染的确认表单字段
func (a *Action) handleRenderConfirmFormFields() (err error) {
	confirmFormFieldsFuncs, err := a.getConfirmFormFieldsFuncs()
	if err != nil {
		return
	}
	if len(confirmFormFieldsFuncs) == 0 {
		return
	}
	fields := make([]form.FieldInterface, 0)
	fieldIdx := map[string]int{}
	var confirmFormFields []form.FieldInterface
	for _, confirmFormFieldsFunc := range confirmFormFieldsFuncs {
		confirmFormFields, err = confirmFormFieldsFunc()
		if err != nil {
			return
		}
		// 字段表单id
		var formId string
		formId, err = a.GetBuilderId()
		if err != nil {
			return
		}
		var code any
		code, err = a.GetActionCode()
		if err != nil {
			return
		}
		formId += fmt.Sprintf("_%v", code)
		var hasAuth bool
		for _, confirmFormField := range confirmFormFields {
			hasAuth, err = confirmFormField.RenderHandle(a.GinContext, formId)
			if err != nil {
				return
			}
			// 没有权限
			if !hasAuth {
				continue
			}
			id, _ := confirmFormField.GetFieldId()
			// 判断原来是否存在
			idx, exists := fieldIdx[id]
			if exists {
				fields[idx] = confirmFormField
			} else {
				fields = append(fields, confirmFormField)
				fieldIdx[id] = len(fields) - 1
			}
		}
	}
	err = a.setConfirmFormFields(fields)
	return
}

// 设置确认弹窗表单字段
// param: func() ([]form.FieldInterface, error)
// param: []form.FieldInterface
// param: form.FieldInterface
func SetConfirmFormFields(a *Action, param ...any) {
	if param == nil {
		return
	}
	if err := a.GetError(); err != nil {
		return
	}
	if a.ConfirmFormFieldsFuncs == nil {
		a.ConfirmFormFieldsFuncs = []func() ([]form.FieldInterface, error){}
	}
	funs := []func() ([]form.FieldInterface, error){}
	for _, item := range param {
		if fun, ok := item.(func() ([]form.FieldInterface, error)); ok {
			funs = append(funs, fun)
			continue
		}
		if itemsValue, ok := item.([]form.FieldInterface); ok {
			funs = append(funs, func() ([]form.FieldInterface, error) {
				return itemsValue, nil
			})
			continue
		}
		if itemValue, ok := item.(form.FieldInterface); ok {
			funs = append(funs, func() ([]form.FieldInterface, error) {
				return []form.FieldInterface{itemValue}, nil
			})
			continue
		}
	}
	a.setConfirmFormFieldsFuncs(funs)
}
